#include<stdio.h>
#include<unistd.h>//execl
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>

//进程替换

//execl:将我们的程序加载到内存中！如何加载？Linux exec* --加载器
//创建子进程的目的:
//1.想让子进程执行父进程代码的一部分。 ---执行父进程对应磁盘代码的一部分
//2.想让子进程执行一个全新的程序。     ---让子进程想办法，加载磁盘上指定的程序，执行程序代码和数据

//原理：
//程序替换的本质，就是将指定程序的代码和数据加载到指定的位置！指定的位置：覆盖子自己的代码和数据
//进程替换的时候没有创建新的进程。所以pid不变


//程序替换中execve系统调用，其他的都是封装，为了让我们有更多的选择

//后面的参数都是从main函数来的，你不写也会向main函数传参int main(int argc,char* argv[] ,....)
// int execl(const char *path, const char *arg, ...);                      ---1.找到 2.如何让执行 3.可变参数列表  --l:list:将参数一个一个的传入exec*
// int execlp(const char *file, const char *arg, ...);                     ---p:path:如何找到程序的公告，带p字符的函数，不用告诉我程序的路径，只要告诉我是谁，我会自动在环境变量PATH进行可执行程序的查找！
// int execle(const char *path, const char *arg, ...,char *const envp[]);  ---e:自定义环境变量
// int execv(const char *path, char *const argv[]);                        ---v.vector:可以将所以的执行参数，放到数组中，统一传递，而不用进行用可变参数方案
// int execvp(const char *file, char *const argv[]);                       ---v,p
// int execvpe(const char* file, char* const argv[],char* const envp[]);
int main()
{
  printf("process is running....\n");
  pid_t id = fork();
  assert(id != -1);

  if(id == 0)
  {

    //类比：命令行怎么写，这里就怎么写
    //execl("/usr/bin/ls","ls","-a","-l","--color=auto",NULL);
    //这里有两个ls，不重复。一个是告诉系统我要执行谁，一个是告诉系统我要怎么执行
    //execlp("ls","ls","-a","-l","--color=auto",NULL);
    


    //char* const argv_[] = {
    //  "ls",
    //  "-a",
    //  "-l",
    //  NULL//必须以NULL结尾
    //};
    ////execv("/usr/bin/ls",argv_);
    //execvp("ls",argv_);
    
    
    //想在这里调用当前路径下我自己写的另一个程序
    //当然，这linux下想替换其他语言的可执行程序也是可以的
    
    //execl("./mybin","mybin",NULL);
    char* const envp_[] = {
      (char*)"MY_VAL=1111112223445678",
      NULL
    };
    //execle("./mybin","mybin",NULL,envp_);//自定义环境变量         ----现象，全局变量为NULL
    
    extern char** environ;
    putenv((char*)"MY_VAL=333333444444");//将指定环境变量导入到系统中，environ指向的环境变量表中
    execle("./mybin","mybin",NULL,environ);//实际上，默认环境变量不传，子进程也能获取
    exit(1);
  }
  //parent
  int status = 0;
  pid_t ret = waitpid(id,&status,0);
  if(ret > 0)
  printf("process wait sucess:%d,exit code:%d,sig number:%d\n",ret,(status>>8)&0xFF,(status&0x7F));

  //.c -> exe -> load -> process -> 运行 -> 执行我们现在所写的代码
  

  //load -> exe
  //只要是一个函数，调用就有可能失败，就是没有替换成功
  //execl("/usr/bin/ls"/*要执行哪一个程序*/,"ls","-a","-l","--color=auto",NULL/*你想怎么执行*/);// all exec* end of NULL:表示没东西传了
  //exec*只有失败才返回-1
  //exec*为什么没有成功返回值呢？因为成功了，就和接下来的代码无关了，判断毫无意义
  //exec*只要返回了，一定是错误了
  //execl("/usr/bin/jedwkjno"/*要执行哪一个程序*/,"ls","-a","-l","--color=auto",NULL/*你想怎么执行*/);// all exec* end of NULL:表示没东西传了




  //这里printf没有被执行，printf也是代码，是在execl之后的，execl执行完毕的时候，代码已经全部被覆盖，开始执行新的程序的代码了，所以printf就无法执行。
  //printf("process running done...\n");
}
